package models

import (
	"math/rand"
	"time"
)

func (*Struct怪物生成表) TableName() string {
	return "怪物生成表"
}

type Struct怪物生成表 struct {
	Id      int32
	IsUse   bool            `xorm:"'is_use'"`
	V区域名称   string          `xorm:"区域名称"`   //凡是这个区域的怪物,将会使用统一的掉宝设定
	V怪物中文名称 string          `xorm:"怪物中文名称"` //怪物中文名称
	V数量     uint8           `xorm:"数量"`
	V生成范围   uint8           `xorm:"生成范围"`
	V活动范围   uint8           `xorm:"活动范围"`
	V坐标     map[int32]int32 `xorm:"坐标"` //X=Y
	V智力     uint8           `xorm:"智力"`
}

type Struct怪物列表 struct {
	Id       int32
	V死亡时间    int //0为死亡 非0为复活时间
	V怪物中文名   string
	V增减_移动速度 int32
	V当前血量    int32
	V当前攻击者   int32
	V跑动时间    int32
	V剩余经验    int32
}

func (this *S空间) 召唤怪物(怪物生成表 *Struct怪物生成表) {
	怪物信息 := m_怪物信息[怪物生成表.V怪物中文名称]
	var 坐标 []*ZUOBIAO
	for x, y := range 怪物生成表.V坐标 {
		坐标 = append(坐标, &ZUOBIAO{X: x, Y: y})
	}
	for i := uint8(0); i < 怪物生成表.V数量; i++ {
		go func() {
			for {
				生存怪 := &Struct怪物列表{}
				生存怪.Id = 怪物生成表.Id //注意，所有怪物的ID关联生成表的ID，这样可以获取掉落的装备
				生存怪.V怪物中文名 = 怪物信息.V中文名称
				生存怪.V当前血量 = 怪物信息.V总血量
				生存怪.V剩余经验 = 怪物信息.V经验值
				rnd := rand.Intn(101)
				找到的坐标 := 坐标[rnd%len(坐标)]
				X := 找到的坐标.X
				Y := 找到的坐标.Y
				if 怪物生成表.V生成范围 != 0 {
					X += int32(rand.Intn(int(怪物生成表.V生成范围)*2)) - int32(怪物生成表.V生成范围)
					Y += int32(rand.Intn(int(怪物生成表.V生成范围)*2)) - int32(怪物生成表.V生成范围)
				}
				位置X, 位置Y := F位置_游戏位置转UE4位置(X, Y)
				地图怪物 := this.F添加内容(E类别_怪物, 位置X, 位置Y, 0, 0, 生存怪)
				怪物_属性计算(地图怪物, 怪物信息)
				switch 怪物生成表.V智力 {
				case 0:
					this.地图_怪物AI(地图怪物, 怪物生成表, 0)
				case 3:
					this.地图_怪物AI(地图怪物, 怪物生成表, 3)
				default:
					this.地图_怪物AI(地图怪物, 怪物生成表, 3)
				}
				//能到这里说明怪已经死了
				动作_怪物死亡(地图怪物)
				this.F删除内容(地图怪物.Id)
				time.Sleep(time.Duration(怪物信息.V死亡后刷新时间) * time.Second)
			}
		}()
	}
}

/*
   智力    主动攻击 	角色走开	 被攻击时     攻击都跑路     攻击者返回
	0       ----       	----  		----        ----           ----
	1       ----       	----        反击         ----          ----
	2       ----       	----        反击         追逐           ----
	3       攻击        ----        反击         追逐
	4       攻击        攻击         攻击         追逐
	5       ----       ----        反击+号令     ----
	6       ----       ----        反击+号令     追逐
	7       攻击        ----         攻击+号令    追逐
	8       攻击        攻击       攻击+号令      追逐
	9       攻击+号令   攻击+号令    攻击+号令     追逐
	10      号令周边    号令周边    号令周边       追逐
*/
func (this *S空间) 地图_怪物AI(地图怪物 *StructMap, 怪物生成表 *Struct怪物生成表, 智力 int) {
	怪物 := 地图怪物.V内容.(*Struct怪物列表)
	怪物信息, ok := m_怪物信息[怪物.V怪物中文名]
	if ok == false {
		panic("不可能")
	}
	if 怪物信息.V死亡后刷新时间 <= 0 { //默认怪物 死亡后刷新时间
		怪物信息.V死亡后刷新时间 = 10
	}
	nextscan := time.Now()
	var 出生X, 出生Y int32
	出生X = 地图怪物.X
	出生Y = 地图怪物.Y
	每秒检测 := time.Now().Add(time.Second)
	闲置时间 := time.Now()
	var 目标位置X, 目标位置Y int32
	状态 := "正常"
	for {
		var 攻击者内容 *StructMap
		距离 := float32(0)
		if 怪物.V当前攻击者 != 0 { //如果有人攻击，那么就向他发送消息
			攻击者内容 = 地图怪物.V空间.F获取内容(怪物.V当前攻击者)
			if (攻击者内容 == nil) || (攻击者内容.V是否死亡 == true) {
				怪物.V当前攻击者 = 0
				攻击者内容 = nil
			} else {
				距离 = 地图怪物.V空间.F计算两点距离(地图怪物.X, 地图怪物.Y, 攻击者内容.X, 攻击者内容.Y)
				if 距离 > m_可视距离 {
					怪物.V当前攻击者 = 0
					攻击者内容 = nil
				}
			}
		}
		if 地图怪物.V基础属性[E基础属性_当前血量] < 0 {
			if 攻击者内容 != nil { //如果有人攻击，那么就向他发送消息
				F地图_发送信息(攻击者内容, &S交换数据{
					V类型:  E交换数据类型_怪物死亡,
					V发送人: 地图怪物,
					V内容:  怪物生成表.V区域名称,
				})
			}
			地图怪物.V是否死亡 = true
			return
		}
		时钟 := time.NewTimer(每秒检测.Sub(time.Now()))
		下次检测 := time.NewTimer(nextscan.Sub(time.Now()))
		func() {
			defer func() {
				时钟.Stop()
				下次检测.Stop()
			}()
			select {
			case 交换数据 := <-地图怪物.VChan: //有来自于其它内容的信息
				if 每秒检测.Sub(time.Now()).Seconds() > 10 {
					每秒检测 = time.Now().Add(time.Second / 2) //反应0.5秒后，开始攻击
				}
				闲置时间 = time.Now()
				原始血量 := 地图怪物.V基础属性[E基础属性_当前血量]
				switch 交换数据.V类型 {
				case E交换数据类型_有人路过, E交换数据类型_攻击效果:
					return
				default:
					重新计算, _, 添加技能, 删除技能 := 地图怪物.F处理接收数据(交换数据)
					if 重新计算 == true {
						怪物_属性计算(地图怪物, 怪物信息)
					}
					for _, 技能名称 := range 删除技能 {
						动作_内容删除辅助技能(地图怪物, 技能名称, 10)
					}
					for _, 技能名称 := range 添加技能 {
						动作_内容加辅助技能(地图怪物, 技能名称, 10)
					}
				}
				怪物.V当前攻击者 = 交换数据.V发送人.Id
				当前血量 := 地图怪物.V基础属性[E基础属性_当前血量]
				掉血 := 原始血量 - 当前血量
				if 掉血 > 0 {
					//掉血需要还给攻击人
					var 增加经验 float32
					if 当前血量 > 0 {
						增加经验 = float32(掉血) * float32(怪物.V剩余经验) / float32(原始血量)
					} else {
						增加经验 = float32(怪物.V剩余经验)
					}
					怪物.V剩余经验 -= int32(增加经验)
					增加经验 *= m_历史长河.V经验倍率
					if 增加经验 != 0 {
						F地图_发送信息(交换数据.V发送人, &S交换数据{
							V类型:  E交换数据类型_增加经验,
							V发送人: 地图怪物,
							V内容:  增加经验,
						})
					}
				}
			case <-时钟.C: //1秒1次的触发，用于系统中血量，辅助技能等
				if time.Now().Sub(闲置时间).Seconds() > 60 { //如果60秒没人来了，那就长期休眠吧
					每秒检测 = 每秒检测.Add(time.Hour)
				} else {
					每秒检测 = 每秒检测.Add(time.Second)
				}
				重新计算, _, 添加技能, 删除技能 := 地图怪物.F检测()
				if 重新计算 == true {
					怪物_属性计算(地图怪物, 怪物信息)
				}
				for _, 技能名称 := range 删除技能 {
					动作_内容删除辅助技能(地图怪物, 技能名称, 10)
				}
				for _, 技能名称 := range 添加技能 {
					动作_内容加辅助技能(地图怪物, 技能名称, 10)
				}
			case <-下次检测.C:
				if 状态 == "移动" {
					var x, y int32
					if 攻击者内容 != nil {
						x = 攻击者内容.X
						y = 攻击者内容.Y
					} else {
						x = 目标位置X
						y = 目标位置Y
					}
					if (攻击者内容 != nil) && (距离 <= 怪物信息.V攻击距离) { //到位置了，开始攻击
						状态 = "正常"
						nextscan = time.Now().Add(time.Millisecond * 100)
						return
					}

					步进 := int32(距离) * 100 / int32(怪物信息.V移动速度*200)
					var newx, newy int32
					if 步进 <= 0 {
						状态 = "正常"
						动作_停止移动(地图怪物)
						if 攻击者内容 == nil { //在正常状态下，如果跑到目标位置，就可以歇一会了
							nextscan = time.Now().Add(time.Second * time.Duration(3+rand.Intn(3)))
						} else {
							nextscan = time.Now().Add(time.Millisecond * 100)
						}
						return
					}
					newx = 地图怪物.X - (地图怪物.X-x)/步进
					newy = 地图怪物.Y - (地图怪物.Y-y)/步进
					地图怪物.F内容移动(newx, newy)
					动作_位置移动(地图怪物, 怪物信息.V移动速度, 地图怪物.X, 地图怪物.Y, newx, newy)
					nextscan = time.Now().Add(time.Second)
					return
				}
				switch 智力 {
				case 0:
					nextscan = time.Now().Add(time.Hour) //智力为0，傻了
					return
				case 3:
					if 攻击者内容 == nil { //如果没有攻击者，则检测攻击都
						if 怪物信息.V移动速度 != 0 && 怪物生成表.V活动范围 != 0 {
							移动距离 := int32(怪物信息.V移动速度 * 400)
							movex := int32(rand.Intn(int(移动距离)*2)) - 移动距离 //正反走
							movey := int32(rand.Intn(int(移动距离)*2)) - 移动距离
							if this.F计算两点距离(出生X, 出生Y, (地图怪物.X+movex), (地图怪物.Y+movey)) > float32(怪物生成表.V活动范围) { //如果距离超出，则数据翻转
								movex *= -1
								movey *= -1
							}
							目标位置X = 地图怪物.X + movex
							目标位置Y = 地图怪物.Y + movey
							状态 = "移动"
							nextscan = time.Now().Add(time.Second * time.Duration(怪物信息.V移动速度))
						}
						if (怪物信息.V移动速度 != 0) && (怪物信息.V主动攻击距离 != 0) {
							周边列表 := this.F找到指定位置四周内容(地图怪物.X, 地图怪物.Y, 怪物信息.V主动攻击距离, uint8(E类别_人物)) //设置自动攻击
							if len(周边列表) != 0 {
								状态 = "移动"
								怪物.V当前攻击者 = 周边列表[0].Id
								nextscan = time.Now().Add(time.Millisecond * 100)
								return
							}
						}
						nextscan = time.Now().Add(time.Second * time.Duration(3+rand.Intn(3))) //在闲置的时候，每三秒进行一次位置转换
						return
					}
					if 距离 <= 怪物信息.V攻击距离 {
						怪物攻击角色(地图怪物, 攻击者内容, 怪物信息)
						nextscan = time.Now().Add(time.Second * 2) //下一次攻击时间，这里可以设置攻击速度
						return
					}
					if 怪物信息.V移动速度 == 0 {
						nextscan = time.Now().Add(time.Second * 2) //下一次攻击时间，这里可以设置攻击速度
						return
					}
					状态 = "移动"
					nextscan = time.Now().Add(time.Millisecond * 100)
				default:
					panic("无效怪物智力")
				}
			}
		}()
	}
}
func (this *StructMap) 找到最近的内容() {

}
func 怪物攻击角色(地图怪物 *StructMap, 攻击者内容 *StructMap, 怪物信息 *Struct怪物信息) {
	周边S := 地图怪物.V空间.F找到指定位置四周内容(地图怪物.X, 地图怪物.Y, m_可视距离, uint8(E类别_人物))
	for _, 内容 := range 周边S {
		if rt0, ok := m_RunTime.Load(内容.V内容.(*S角色列表).V名字); ok == true {
			rt := rt0.(*RunTime)
			switch 怪物信息.V攻击类型 {
			case "远程物理":
				rt.动作_远程物理攻击(地图怪物.Id, 攻击者内容.Id, 地图怪物.X, 地图怪物.Y, 怪物信息.V技能名称)
			case "魔法":
				rt.动作_魔法攻击(地图怪物.Id, 攻击者内容.Id, 地图怪物.X, 地图怪物.Y, 怪物信息.V技能名称)
			default:
				怪物信息.V技能名称 = "BasicAtk1"
				rt.动作_怪物攻击内容(地图怪物.Id, 攻击者内容.Id, 地图怪物.X, 地图怪物.Y, 怪物信息.V技能名称)
				rt.动作_人物受到攻击(怪物信息.V技能名称, 0)
			}
			break
		}
	}
	//B掉血, B掉蓝, 效果 := A攻击B(地图怪物.V基础属性, rt.V角色内容.V基础属性, 攻击类型)
	属性 := make(map[uint16]float32)
	for k, v := range 地图怪物.V基础属性 {
		属性[k] = v
	}
	F地图_发送信息(攻击者内容, &S交换数据{
		V类型:  E交换数据类型_攻击,
		V发送人: 地图怪物,
		V内容:  属性,
	})
}

func 怪物_属性计算(地图怪物 *StructMap, 怪物信息 *Struct怪物信息) {
	for k, v := range 怪物信息.V自身属性 {
		地图怪物.V基础属性[k] = v
	}
	地图怪物.V基础属性[E基础属性_总血量] = float32(怪物信息.V总血量)
	地图怪物.V基础属性[E基础属性_当前血量] = float32(怪物信息.V总血量)
}
